這一篇我們就來討論 PttCrawler 如何進行測試,首頁我們先來看看我們目前『可能』的程式碼
<?php
// src/PttCrawler.php
namespace Recca0120\Ithome30;
use Psr\Http\Client\ClientInterface;
use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;
class PttCrawler
{
public function __construct(private ClientInterface $httpClient)
{
}
public function all()
{
$crawler = new Home($this->httpClient);
$boardCrawler = new Board($this->httpClient);
$results = [];
foreach ($crawler->all() as $board) {
foreach ($boardCrawler->fetch($board) as $articles) {
$results[] = $articles;
}
}
return $results;
}
}
在 construct 是注入一個 ClientInterface,在 method all 即是 new Home 及 new Board 這兩個物件,這樣我們想要用 Mock 來模擬回傳值會變的非常的不容易,所以我們可以先把程式碼調整為
<?php
// src/PttCrawler.php
namespace Recca0120\Ithome30;
use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;
class PttCrawler
{
public function __construct(private Home $home, private Board $board)
{
}
public function all()
{
$results = [];
foreach ($this->home->all() as $board) {
foreach ($this->board->fetch($board) as $articles) {
$results[] = $articles;
}
}
return $results;
}
}
construct 改為注入 Home, Board,這樣我們就可以直接針對 Home 及 Board 來進行 mock 後,再注入到 PttCrawler 了。
這時候我們可以先打開 HomeTest 觀察 all 的回傳值,及打開 BoardTest 的回傳值,立刻就可以模擬出 Home 及 Board 的回傳資料,我們就可以寫出以下的測試程式碼
<?php
namespace Recca0120\Ithome30\Tests;
use Mockery;
use PHPUnit\Framework\TestCase;
use Recca0120\Ithome30\PttCrawler;
use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;
class PttCrawlerTest extends TestCase
{
public function test_fetch_board_page()
{
/** @var Mockery\Mock|Home $home */
$home = Mockery::mock(Home::class);
$home->allows('all')->andReturn([[
'name' => 'Gossiping',
"nuser" => '8803',
'class' => '綜合',
'title' => '[八卦] 亞運李智凱、許皓鋐奪金!',
'url' => 'https://www.ptt.cc/bbs/Gossiping/index.html'
]]);
/** @var Mockery\Mock|Board $board */
$board = Mockery::mock(Board::class);
// 因為 fetch 回傳 Generator 所以我們必須用 andReturnUsing + Closure 來模擬回傳值
$board->allows('fetch')->andReturnUsing(function () {
yield [
'board_name' => 'Gossiping',
'board_class' => '綜合',
'nrec' => '4',
'type' => '問卦',
'title' => '司機夫人真的有去卡地亞血拚$1.1M嗎?',
'author' => 'uwmtsa',
'date' => '10/06',
'url' => 'https://www.ptt.cc/bbs/Gossiping/M.1696537444.A.1A5.html',
];
});
$crawler = new PttCrawler($home, $board);
$records = $crawler->all();
self::assertEquals([
'board_name' => 'Gossiping',
'board_class' => '綜合',
'nrec' => '4',
'type' => '問卦',
'title' => '司機夫人真的有去卡地亞血拚$1.1M嗎?',
'author' => 'uwmtsa',
'date' => '10/06',
'url' => 'https://www.ptt.cc/bbs/Gossiping/M.1696537444.A.1A5.html',
], $records[0]);
}
}
接著再執行測試,如果得到紅燈就再去調整 PttCrawler 的程式碼,如果得到綠燈則表示程式碼正確!